#include "UltimateOpenALPrecompiled.h"
#include "GameAudio.h"
#include <AL/alut.h>

ALuint GameAudio::loadFile(const char* filename)
{
	ALenum error;
	ALuint newBuffer;
	ALUT_SAFE_CALL(newBuffer = alutCreateBufferFromFile(filename), "Cannot load audio file: " + Ogre::String(filename));        
	return newBuffer;
}

void GameAudio::createSource(ALuint* source)
{
	AL_SAFE_CALL(alGenSources (1, source), "Unable to generate source");
}

GameAudio::GameAudio()
{

}

GameAudio::GameAudio(int argc, char** argv)
{
	printf("*** Initializing OpenAL ***\n");
        
    alutInit (&argc, argv);

	ALenum error;
	sourceMap.clear();

	// helloAudioWorld();

	error = alutGetError();
	if(error != AL_NO_ERROR)
	{
		// Ogre::LogManager::getSingleton().logMessage("Cannot load audio file: "+ Ogre::String(alutGetErrorString(error)));
	}

}

// Hello World for OpenAL
void GameAudio::helloAudioWorld()
{
	ALuint helloBuffer, helloSource;

	helloBuffer = alutCreateBufferHelloWorld ();

	alGenSources (1, &helloSource);
	alSourcei (helloSource, AL_BUFFER, helloBuffer);

	alSourcei (helloSource, AL_LOOPING, AL_FALSE);
	alSourcei (helloSource, AL_GAIN, 10);
	alSourcef (helloSource, AL_PITCH, 1.0);
		
	float musicVolume = 10;
	alSourcei (helloSource, AL_GAIN, musicVolume);

	alListener3f(AL_POSITION, 0,0,0);
	alSource3f(helloSource, AL_POSITION, -1,0,0);

	alSourcePlay (helloSource);
}

Ogre::Vector3 GameAudio::getAudioListenerPosition()
{
	float* pos;
	//alGetListener(AL_POSITION, pos);

	// TODO

	return Ogre::Vector3::ZERO;
}

Ogre::Vector3 GameAudio::getAudioListenerDirection()
{
	// TODO

	return Ogre::Vector3::ZERO;
}

void GameAudio::setAudioListenerPose(Ogre::Vector3 pos, Ogre::Vector3 dir)
{
	alListener3f(AL_POSITION, pos.x, pos.y, pos.z);
	float orient[] = {dir.x, dir.y, dir.z, 0, 1, 0};
	alListenerfv(AL_ORIENTATION, orient);
}

// Create audio source with: name, filepath (buffer), loop, pitch, position
// Does not play the actual audio
void GameAudio::createAudioWithName(
	Ogre::String name, Ogre::String filePath, bool looping = false,
	float pitch = 1.0, Ogre::Vector3 position = Ogre::Vector3::ZERO)
{

	ALuint buffer = loadFile(filePath.c_str());
	ALuint source;
	createSource(&source);

	AL_SAFE_CALL(alSourcei (source, AL_BUFFER, buffer), "unable to bind buffer");
	if (looping)
		AL_SAFE_CALL(alSourcei (source, AL_LOOPING, AL_TRUE), "unable to set looping");
	AL_SAFE_CALL(alSourcef (source, AL_PITCH, pitch), "unable to set pitch");
	AL_SAFE_CALL(alSource3f (source, AL_POSITION, position.x, position.y, position.z), "unable to set position");

	sourceMap[name.c_str()] = source;

}

// Alter the named audio source with: filepath (buffer), loop, pitch, position
// Does not play the actual audio
void GameAudio::setAudioWithName(
	Ogre::String name, Ogre::String filePath, bool looping = false,
	float pitch = 1.0, Ogre::Vector3 position = Ogre::Vector3::ZERO)
{

	ALuint buffer = loadFile(filePath.c_str());
	ALuint source = sourceMap[name.c_str()];

	AL_SAFE_CALL(alSourcei (source, AL_BUFFER, buffer), "unable to bind buffer");
	if (looping)
		AL_SAFE_CALL(alSourcei (source, AL_LOOPING, AL_TRUE), "unable to set looping");
	AL_SAFE_CALL(alSourcef (source, AL_PITCH, pitch), "unable to set pitch");
	AL_SAFE_CALL(alSource3f (source, AL_POSITION, position.x, position.y, position.z), "unable to set position");

}

// Plays the named audio
void GameAudio::playAudioByName(Ogre::String name)
{
	ALuint source = sourceMap[name.c_str()];
	AL_SAFE_CALL(alSourcePlay (source), "unable to play title source");
}

// Create audio source: filepath (buffer), loop, pitch, position
// Plays the actual audio, but doesnt store it
void GameAudio::playAudioFromFile(Ogre::String filePath, bool looping = false,
	float pitch = 1.0, Ogre::Vector3 position = Ogre::Vector3::ZERO)
{
	ALuint buffer = loadFile(filePath.c_str());
	ALuint source;
	createSource(&source);

	AL_SAFE_CALL(alSourcei (source, AL_BUFFER, buffer), "unable to bind buffer");
	if (looping)
		AL_SAFE_CALL(alSourcei (source, AL_LOOPING, AL_TRUE), "unable to set looping");
	AL_SAFE_CALL(alSourcef (source, AL_PITCH, pitch), "unable to set pitch");
	AL_SAFE_CALL(alSource3f (source, AL_POSITION, position.x, position.y, position.z), "unable to set position");
		
    AL_SAFE_CALL(alSourcePlay (source), "unable to play source");
}

// Stops named audio source
void GameAudio::stopAudioByName(Ogre::String name)
{
	ALuint source = sourceMap[name.c_str()];
	AL_SAFE_CALL(alSourceStop (source), "unable to stop" + name + "source");
}

// Stops all audio
void GameAudio::stopAllAudioSource()
{
	std::map<std::string, ALuint>::iterator i = sourceMap.begin();
	for( ; i != sourceMap.end(); ++i )
	{
		// i->first is the key
		// i->second is it's value
		AL_SAFE_CALL(alSourceStop(i->second), "unable to stop" + i->first + "source");
	}

}
	
void GameAudio::deleteAllAudioSource()
{
	stopAllAudioSource();
	sourceMap.clear();
}
    
GameAudio::~GameAudio()
{
    printf("*** Shutting down OpenAL ***\n");

	deleteAllAudioSource();
        
    alutExit();
}